package com.woniuxy.handler;

import com.woniuxy.service.SecurityService;
import com.woniuxy.util.CONSTANT;
import com.woniuxy.util.GetUserContent;
import com.woniuxy.util.JWTUtil;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author HP
 * 校验系统jwt是否合法
 * 在springBoot中，不建议直接实现Filter来声明一个过滤器
 * 发送请求(queryGood) -> 过滤器 -> controller -> 请求转发("/queryAll")/重定向
 * -> 过滤器: 过滤器执行两次
 * OncePerRequestFilter: 当前请求只会走一次该过滤器,不会重复执行
 *
 * 实现步骤:
 * 1.获取请求头中的jwt
 *
 * 2.解密jwt
 *
 * 3，获取redis中的jwt前端和后端的jwt进行对比
 *
 * 4.对jwt续期
 *
 * 5.把登录凭证放入容器
 *    因为后续过滤器会尝试获取登录凭证，如果说获取不到会被未登录处理器拦截
 *
 */
@Component
public class JWThandler extends OncePerRequestFilter {

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private SecurityService securityService;

    @SneakyThrows
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest,
                                    HttpServletResponse httpServletResponse,
                                    FilterChain filterChain)
            throws ServletException, IOException {
        //获取请求头中的jwt
        String headerJWT = httpServletRequest.getHeader(CONSTANT.JWT);
        if (headerJWT == null){
            //请求头中没有带jwt,把请求放行即可,不能在这里拦截
            //因为拦截了，后续的过滤器就不会执行了
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
        //解密jwt
        if (!JWTUtil.decode(headerJWT) ){
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }

        //3.获取redis中的jwt前端和后端的jwt进行对比
        Map userInfo = GetUserContent.getUserInfo();
        Long userId = (long)userInfo.get(CONSTANT.USER_ID);
        String redisJWT =(String) redisTemplate.opsForValue().get(CONSTANT.LOGIN_USER_JWT + userId);
        if(!headerJWT.equals(redisJWT)){
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }

        //4.对jwt续期
        redisTemplate.opsForValue().set(CONSTANT.JWT + userId,headerJWT,30, TimeUnit.MINUTES);

        //5.把登录凭证放入容器
        //怎么获取用户账号密码权限
        String account = (String) userInfo.get("account");
        UserDetails userDetails = securityService.loadUserByUsername(account);
        UsernamePasswordAuthenticationToken upat =
                new UsernamePasswordAuthenticationToken
                        (userDetails.getUsername(),
                userDetails.getPassword(),userDetails.getAuthorities());

        SecurityContextHolder.getContext().setAuthentication(upat);

        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }
}
